package channelsignal

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
)

//匿名管道

// 文件缓存区(缺点：一次只能解决一个)
func RunCmd() {
	// 抓取管道
	pingCmd := exec.Command("tasklist") //exec.Command("ping","www.qq.com")

	// 跟踪路由
	//exec.Command("tracert","www.qq.com") //最多跳跃30个节点来检测到QQ

	stdOut, stdOutErr := pingCmd.StdoutPipe() //输出
	if nil != stdOutErr {
		fmt.Println("stdOutErr:", stdOutErr)
		return
	}

	// 开始执行
	if startErr := pingCmd.Start(); nil != startErr {
		fmt.Println("startErr:", startErr)
		return
	}

	bufferIO := false

	if !bufferIO {
		// 二进制保存
		var outBuffer bytes.Buffer
		for {
			tempOutPutList := make([]byte, 256)
			// 读取二进制
			readOut, readOutErr := stdOut.Read(tempOutPutList)
			if nil != readOutErr {
				// 读到文件的最后
				if io.EOF == readOutErr {
					break
				} else {
					fmt.Println("readOutErr:", readOutErr)
					return
				}

			}

			if readOut > 0 {
				// 读取到的写入
				outBuffer.Write(tempOutPutList[:readOut])
			}

		}

		fmt.Println(outBuffer.String())

	} else {
		stdOutReader := bufio.NewReader(stdOut)

		lineByteList, _, readerErr := stdOutReader.ReadLine()
		if nil != readerErr {
			return
		}

		// 读取行
		fmt.Println(string(lineByteList))
	}
}

// 匿名管道进程通信
func RunCmdPipe() {
	command := exec.Command("tasklist")
	// 输出
	var outPutBuffer bytes.Buffer
	// 设置输出
	command.Stdout = &outPutBuffer

	// 开启执行
	if startErr := command.Start(); nil != startErr {
		fmt.Println("startErr:", startErr)
		return
	}

	// 等待
	if waitErr := command.Wait(); nil != waitErr {
		fmt.Println("waitErr:", waitErr)
		return
	}

	fmt.Printf("%s", outPutBuffer.Bytes())

}

// MemoryPipe -- 内存管道
func MemoryPipe() {
	// 内存管道
	reader, witer := io.Pipe()
	go func() {
		outPut := make([]byte, 100)
		dataLen, readErr := reader.Read(outPut)
		if nil != readErr {
			fmt.Println("readErr:", readErr)
			return
		}

		fmt.Println("read:", dataLen)

	}()

	input := make([]byte, 26)

	for i := 65; i <= 90; i++ {
		// 加入字母
		input[i-65] = byte(i)
	}

	writeLen, witerErr := witer.Write(input)
	if nil != witerErr {
		fmt.Println("witerErr:", witerErr)
		return
	}

	fmt.Println("witer:", writeLen)

	time.Sleep(3 * time.Second)

	return
}

// SystemPipe -- 系统管道
func SystemPipe() {
	// 系统管道
	reader, witer, pipeErr := os.Pipe()
	if nil != pipeErr {
		fmt.Println("pipeErr:", pipeErr)
		return
	}

	go func() {
		outPut := make([]byte, 100)
		dataLen, readErr := reader.Read(outPut)
		if nil != readErr {
			fmt.Println("readErr:", readErr)
			return
		}

		fmt.Println("read:", dataLen)

	}()

	input := make([]byte, 16)

	for i := 65; i <= 80; i++ {
		// 加入字母
		input[i-65] = byte(i)
	}

	writeLen, witerErr := witer.Write(input)
	if nil != witerErr {
		fmt.Println("witerErr:", witerErr)
		return
	}

	fmt.Println("witer:", writeLen)

	time.Sleep(3 * time.Second)

	return
}

// StartSendSignal -- 开始进程信号通信
func StartSendSignal() {
	// 发送信号
	go func() {
		time.Sleep(5 * time.Second)
		SendSignal()

	}()

	// 接收信号
	AcceptSignal()
}

// GetCmdText -- 读取命令内容
func GetCmdText(cmd *exec.Cmd) string {
	var buffer bytes.Buffer
	// 写入路径
	buffer.WriteString(cmd.Path)

	// 从第一个写到最后
	for _, arg := range cmd.Args[1:] {
		buffer.WriteRune(' ')
		buffer.WriteString(arg)
	}

	return buffer.String()
}

// GetPidList -- 获取进程编号
func GetPidList(strList []string) ([]int, error) {
	var pidList []int

	for _, str := range strList {
		fmt.Println("getPid:", str)

		pid, pidErr := strconv.Atoi(strings.TrimSpace(str))
		if nil != pidErr {
			return nil, pidErr
		}
		pidList = append(pidList, pid)

	}

	return pidList, nil
}

// RunCmdList --
func RunCmdList(cmdList []*exec.Cmd) ([]string, error) {
	if nil == cmdList || 0 == len(cmdList) {
		return nil, errors.New("cmdList 为空!")
	}

	first := true

	var outPut []byte

	for _, cmd := range cmdList {
		fmt.Println("Run Command", GetCmdText(cmd))
		if !first {
			var stdinBuffer bytes.Buffer
			// 写入
			stdinBuffer.Write(outPut)
			// 设置输入
			cmd.Stdin = &stdinBuffer

		}

		var stdoutBuffer bytes.Buffer
		// 设定输出
		cmd.Stdout = &stdoutBuffer

		// 开启命令
		if startErr := cmd.Start(); nil != startErr {
			return nil, startErr
		}

		// 等待命令
		if waitErr := cmd.Wait(); nil != waitErr {
			return nil, waitErr
		}

		// 输出
		outPut = stdoutBuffer.Bytes()

		// 第一个命令的结果当作第二次命令的写入
		if first {
			first = false
		}

	}

	var (
		lines        []string
		outPutBuffer bytes.Buffer
	)

	// 写入
	outPutBuffer.Write(outPut)

	for {
		// 读取
		line, lineErr := outPutBuffer.ReadBytes('\n')
		fmt.Println("line:", string(line))
		if nil != lineErr {
			// 结束
			if io.EOF == lineErr {
				break
			}
			fmt.Println("lineErr:", lineErr)
			return nil, lineErr
		}
		lines = append(lines, string(line))
	}

	return lines, nil

}

// SendSignal --发送信号
func SendSignal() {
	cmdList := []*exec.Cmd{
		exec.Command("tasklist"),
		exec.Command("ipconfig"),
	}

	// 执行命令
	outPut, outPutErr := RunCmdList(cmdList)
	if nil != outPutErr {
		fmt.Println("outPutErr:", outPutErr)
		return
	}

	// 获取进程编号
	pidList, pidListErr := GetPidList(outPut)

	fmt.Println("pidList:", pidList)

	if nil != pidListErr {
		fmt.Println("pidListErr:", pidListErr)
		return
	}

	for _, pid := range pidList {
		// 抓取进程
		proc, procErr := os.FindProcess(pid)
		if nil != procErr {
			fmt.Println("procErr:", procErr)
			return
		}

		// 退出
		sig := syscall.SIGQUIT

		fmt.Println("发送信号:", sig, pid)

		// 发送信号
		if signalErr := proc.Signal(sig); nil != signalErr {
			fmt.Println("signalErr:", signalErr)
			return
		}

	}

}

// AcceptSignal --接收信号
func AcceptSignal() {

	// 创建管道
	signalReceive1 := make(chan os.Signal, 1)

	// 信号
	signalList1 := []os.Signal{syscall.SIGINT, syscall.SIGQUIT}

	// 接收
	fmt.Println("signalReceive1:", signalReceive1)

	// 通知
	signal.Notify(signalReceive1, signalList1...)

	signalReceive2 := make(chan os.Signal, 2)

	signalList2 := []os.Signal{syscall.SIGINT, syscall.SIGQUIT}

	fmt.Println("signalReceive2:", signalReceive2)

	// 通知
	signal.Notify(signalReceive2, signalList2...)

	// 等待一下
	var waitGroup sync.WaitGroup
	// 等待2个
	waitGroup.Add(2)

	go func() {
		for sig1 := range signalReceive1 {
			fmt.Println("Receive1:", sig1)
		}
		fmt.Println("Receive1:", "over")
		waitGroup.Done()
	}()

	go func() {
		for sig2 := range signalReceive2 {
			fmt.Println("Receive2:", sig2)
		}
		fmt.Println("Receive2:", "over")
		waitGroup.Done()
	}()

	fmt.Println("waiting for 25 seconds")
	time.Sleep(25 * time.Second)

	fmt.Println("Stop Notify 1")
	// 停止
	signal.Stop(signalReceive1)
	// 关闭管道
	close(signalReceive1)

	fmt.Println("signalReceive2 Over")

	fmt.Println("waiting for 26 seconds")
	time.Sleep(26 * time.Second)

	fmt.Println("Stop Notify 2")
	// 停止
	signal.Stop(signalReceive2)
	// 关闭管道
	close(signalReceive2)

	fmt.Println("signalReceive2 Over")

	waitGroup.Wait()

	return
}
